#ifndef __WIN_THREAD_H__
  #define __WIN_THREAD_H__

#include <windows.h>

//! Simple wrapper for thread

/*!
This is a wrapper for a MS-Windows thread.

Implementation date: 2008

Usage:
\code
// this class MUST have a default constructor & a virtual destructor
class test_thread : public win_thread {
private:
  record_set rs;

public:
  virtual unsigned long run() {
    try {
      string str_cnv;
      converter::to_string((unsigned int) get_thread_id(), str_cnv);
      str_cnv = "Thread " + str_cnv + ".log";

      odbc_database db;
      db.connect("DSN=MSQL;", str_cnv);
      db.execute_query("SELECT * FROM PERSON;", rs);

      ostringstream oss;
      oss << rs;

      logger::log(str_cnv, oss.str(), true, true); // writes the records selected from the database to a file

    } catch (const general_exception &ge) {
      cerr << ge.get_message() << endl;
      cerr << ge.get_info() << endl;
    }

    return 0;
  }

  test_thread() {
    // nothing to do
  }

  virtual ~test_thread() {
    // nothing to do
  }
};
\endcode

test_thread can be used like this:

\code
int main(int argc, char *argv[]) {
  const int threads = 4;
  test_thread tt[threads];
  for (int i = 0; i < threads; ++i)
    tt[i].start();

  for (int i = 0; i < threads; ++i)
    tt[i].wait(); // waits for all threads to finish their jobs

  return EXIT_SUCCESS;
}
\endcode
*/

class win_thread {
private:
  HANDLE hThread;
  DWORD dwThreadId;
  bool is_running;

  //! blocks until the thread returns and then closes the thread handle
  void release();

protected:

  //! sub-classes must check this variable in the overridden run method
  bool stop_requested;

public:

  //! must be overridden by each sub-class
  virtual unsigned long run() = 0;

  //! returns the thread-id
  virtual unsigned long get_thread_id() const;

  //! starts the thread and calls the run method of the sub-class (may thrown an exception)
  void start();

  //! sets the 'stop_requested' variable to true and blocks until the thread returns
  void stop();

  //! blocks until the thread returns
  void wait();

  //! constructor
  win_thread();

  //! destructor
  virtual ~win_thread();
};

#endif
